package triannon.client.components;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JViewport;

import triannon.client.sprites.Background;
import triannon.client.sprites.ISprite;
import triannon.client.util.ResourceLocator;

/**
 * Small version of the MapView for overview and easy navigation.
 * 
 * @since 17.11.2009
 * @author Stephan
 */
@SuppressWarnings("serial")
public class MiniMap extends JComponent {
	private final IDrag draggable;
	private final JScrollPane scrollPane;
	private double scale = 1.0;

	private final int miniMapWidth; // how the width will always be
	private int miniMapHeight;

	private double width, height;

	private boolean showSprites, showBackground;

	private BufferedImage bi = null; // background image that will be painted

	private final Rectangle selectionRect = new Rectangle();

	public MiniMap(IDrag draggable, JScrollPane scrollPane, int width) {
		this.draggable = draggable;
		this.scrollPane = scrollPane;
		this.miniMapWidth = width;

		setShowItems(true);
		setShowBackground(false);

		MouseAdapter mouseAdapter = new MiniMapMouseListener();

		addMouseListener(mouseAdapter);
		addMouseMotionListener(mouseAdapter);
	}

	public void setImage(String fileName) {
		if (bi == null) {
			bi = ResourceLocator.getImage(fileName);

			setOriginalSize(bi.getWidth(), bi.getHeight());
		}

		setVisible(true);
		repaint();
	}

	public void setOriginalSize(int width, int height) {
		this.width = width;
		this.height = height;

		scale = miniMapWidth / this.width;
		miniMapHeight = (int) Math.round(this.height * scale);

		setSize(miniMapWidth, miniMapHeight);
		setVisible(true);
		repaint();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
	 * 
	 * Overridden method to paint the MiniMap
	 * 
	 * @since 17.11.2009 @author Stephan
	 */
	@Override
	protected void paintComponent(Graphics graphics) {
		try {

			double tmpScale = scale / draggable.getScale();

			Graphics2D g = (Graphics2D) graphics;

			// paint the background
			g.setColor(Color.BLACK);
			g.fillRect(0, 0, miniMapWidth, miniMapHeight);

			// paint the mini background image
			if (bi != null && showBackground) {
				RenderingHints qualityHints = new RenderingHints(
						RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
				qualityHints.put(RenderingHints.KEY_RENDERING,
						RenderingHints.VALUE_RENDER_SPEED);

				g.setRenderingHints(qualityHints);

				g.drawImage(bi, 0, 0, miniMapWidth, miniMapHeight, null);
			}

			if (showSprites) {
				int mX, mY, mWidth, mHeight;

				// paint all mini sprites
				for (ISprite m : draggable.getTiles()) {
					if (!(m instanceof Background)) {
						mX = (int) Math.round(m.getX() * tmpScale);
						mY = (int) Math.round(m.getY() * tmpScale);
						mWidth = (int) Math.round(m.getWidth() * tmpScale);
						mHeight = (int) Math.round(m.getHeight() * tmpScale);

						Color c = m.getBKColor();
						g.setColor(c);

						g.fillRect(mX, mY, mWidth, mHeight);
					}
				}
			}

			// paint the minimap frame
			g.setColor(Color.BLACK);
			g.drawRect(0, 0, miniMapWidth - 1, miniMapHeight - 1);

			// paint the selection frame
			JViewport vp = scrollPane.getViewport();

			int tmpWidth = (int) (scrollPane.getWidth() * tmpScale) - 3;
			tmpWidth = Math.min(miniMapWidth - 3, tmpWidth);
			tmpWidth = Math.max(2, tmpWidth);

			int tmpHeight = (int) (scrollPane.getHeight() * tmpScale) - 3;
			tmpHeight = Math.min(miniMapHeight - 3, tmpHeight);
			tmpHeight = Math.max(2, tmpHeight);

			selectionRect.setRect(vp.getViewPosition().x * tmpScale + 1, (vp
					.getViewPosition().y * tmpScale) + 1, tmpWidth, tmpHeight);

			g.setColor(Color.LIGHT_GRAY);
			g.drawRect(selectionRect.x, selectionRect.y, selectionRect.width,
					selectionRect.height);

		} catch (NullPointerException e) {
			e.printStackTrace();
		}

		super.paintComponent(graphics);
	}

	@Override
	public Dimension getPreferredSize() {
		return new Dimension(miniMapWidth, miniMapHeight);
	}

	@Override
	public Dimension getMinimumSize() {
		return getPreferredSize();
	}

	@Override
	public Dimension getMaximumSize() {
		return getPreferredSize();
	}

	public void clearBufferedImage() {
		bi = null;
	}

	private class MiniMapMouseListener extends MouseAdapter {

		@Override
		public void mousePressed(MouseEvent e) {
			// if pressed with left, remember the position
			if (e.getButton() == 1) {
				int x = e.getX();
				int y = e.getY();

				if (y > Math.round(height * scale)) {
					return;
				}

				// if clicked, go directly to the position
				int vX = (int) Math.round(x / (scale / draggable.getScale()));
				int vY = (int) Math.round(y / (scale / draggable.getScale()));

				draggable.setViewPort(vX, vY);
			}

			repaint();
		}

		@Override
		public void mouseDragged(MouseEvent e) {
			// if dragged, move the position
			int x = e.getX();
			int y = e.getY();

			if (y > Math.round(height * scale)) {
				return;
			}

			int vX = (int) Math.round(x / (scale / draggable.getScale()));
			int vY = (int) Math.round(y / (scale / draggable.getScale()));

			draggable.setViewPort(vX, vY);

			repaint();
		}
	}

	public void setShowItems(boolean showItems) {
		this.showSprites = showItems;
		repaint();
	}

	public void setShowBackground(boolean showBackground) {
		this.showBackground = showBackground;
		repaint();
	}
}
